package day28.homework;

/**
 * 死锁示例
 * 
 * 死锁产生的四个必要条件：
 * 1. 互斥条件：一个资源每次只能被一个进程使用
 * 2. 请求与保持条件：一个进程因请求资源而阻塞时，对已获得的资源保持不放
 * 3. 不剥夺条件：进程已获得的资源，在未使用完之前，不能强行剥夺
 * 4. 循环等待条件：若干进程之间形成一种头尾相接的循环等待资源关系
 * 
 * 本示例演示了两个线程如何因为争夺两个锁资源而产生死锁：
 * - 线程1持有lock1锁，请求lock2锁
 * - 线程2持有lock2锁，请求lock1锁
 * - 两者互相等待对方释放锁，形成死锁
 */
public class hw12 {
    // 创建两个对象锁，作为共享资源
    // lock1和lock2分别代表两个不同的资源
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        // 创建线程1：按照lock1->lock2的顺序获取锁
        Thread thread1 = new Thread(() -> {
            // 获取lock1对象锁，成功进入同步代码块
            synchronized (lock1) {
                System.out.println("线程1获取了lock1锁");
                try {
                    // 线程1稍微延迟100毫秒，确保线程2也有时间启动并获取lock2
                    // 这个延迟是制造死锁的关键步骤
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程1尝试获取lock2锁...");
                // 此时线程1持有lock1锁，尝试获取lock2锁
                // 但lock2锁已经被线程2持有，所以线程1在此处阻塞等待
                synchronized (lock2) {
                    // 这段代码永远不会执行，因为线程2也在等待lock1锁
                    System.out.println("线程1获取了lock2锁");
                }
            }
        });

        // 创建线程2：按照lock2->lock1的顺序获取锁
        // 与线程1获取锁的顺序相反，这是产生死锁的根源
        Thread thread2 = new Thread(() -> {
            // 获取lock2对象锁，成功进入同步代码块
            synchronized (lock2) {
                System.out.println("线程2获取了lock2锁");
                try {
                    // 线程2稍微延迟100毫秒，确保线程1也有时间启动并获取lock1
                    // 这个延迟同样是制造死锁的关键步骤
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程2尝试获取lock1锁...");
                // 此时线程2持有lock2锁，尝试获取lock1锁
                // 但lock1锁已经被线程1持有，所以线程2在此处阻塞等待
                synchronized (lock1) {
                    // 这段代码永远不会执行，因为线程1也在等待lock2锁
                    System.out.println("线程2获取了lock1锁");
                }
            }
        });

        // 启动两个线程，开始竞争锁资源
        thread1.start();
        thread2.start();

        // 等待线程结束，但在死锁情况下，这两个线程永远不会结束
        // 因为它们互相等待对方释放锁资源，形成僵局
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 这行代码永远不会被执行，因为程序已经陷入死锁
        System.out.println("程序结束");
    }
}